嗨大家好,今天是第七天,終於過了一個禮拜,每天下班運動完都覺得時間不夠用啊啊啊
命令模式最常見的場景應用是:
有時候需要像某些物件發送請求,但是並不知道請求的接收者是誰,也不知道被請求的操作是什麼。此時希望用一種鬆耦合的方式來設計程式,使得請求發送者和請求接收者能夠消除彼此之間的耦合關係
用個常見的例子舉例,寫網頁的時候很可能畫面上會有很多按鈕,大型專案可能會將繪製按鈕功能與實際功能分給不同工程師來做,當繪製工程師做出按鈕時並不知道實際功能是什麼,那麼要怎麼綁定按鈕事件呢?我們可以用命令模式來試試:
首先先做畫面
var $btn1, $btn2, $btn3;
(function () {
$btn1 = createBtn('btn1');
$btn2 = createBtn('btn2');
$btn3 = createBtn('btn3');
function createBtn(id) {
return $('<button>').attr('id', id).text(id).appendTo('body');
}
})();
再來做一個setCommand函數,此函數要往按鈕綁定命令
var setCommand = function ($btn, command) {
$btn.click(function () {
command.execute();
});
}
這時候繪製工程師任務算是結束了,剩下由實作功能工程師來完成,假設他們做了“MenuBar Refresh(選單更新)”、“submenu add(增加子選單)”、“submenu del(刪除子選單)”功能,這幾個功能分佈在MenuBar和SubMenu兩個物件中
var MenuBar = {
refresh: function () {
console.log('MenuBar Refresh');
}
};
var SubMenu = {
add: function () {
console.log('submenu add');
},
del: function () {
console.log('submenu del');
}
};
接下來我們要將這些行為封裝在命令類別中
var RefreshMenuBarCommand = function (receiver) {
this.receiver = receiver;
};
RefreshMenuBarCommand.prototype.execute = function () {
this.receiver.refresh();
};
var AddSubMenuCommand = function (receiver) {
this.receiver = receiver;
};
AddSubMenuCommand.prototype.execute = function () {
this.receiver.add();
};
var DelSubMenuCommand = function (receiver) {
this.receiver = receiver;
};
DelSubMenuCommand.prototype.execute = function () {
this.receiver.del();
};
接下來產生command物件,並安裝到按鈕上
var refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar);
var addSubMenuCommand = new AddSubMenuCommand(SubMenu);
var delSubMenuCommand = new DelSubMenuCommand(SubMenu);
setCommand($btn1, refreshMenuBarCommand);
setCommand($btn2, addSubMenuCommand);
setCommand($btn3, delSubMenuCommand);
以上就完成簡單的命令模式。
但是怎麼感覺這個命令模式很奇怪還要多一些command、receiver物件好像把事情復雜了,感覺有更簡單的寫法
var $btn1, $btn2, $btn3;
(function () {
$btn1 = createBtn('btn1');
$btn2 = createBtn('btn2');
$btn3 = createBtn('btn3');
function createBtn(id) {
return $('<button>').attr('id', id).text(id).appendTo('body');
}
})();
var bindClick = function ($btn, callback) {
$btn.click(callback);
}
var MenuBar = {
refresh: function () {
console.log('MenuBar Refresh');
}
};
var SubMenu = {
add: function () {
console.log('submenu add');
},
del: function () {
console.log('submenu del');
}
};
bindClick($btn1, MenuBar.refresh);
bindClick($btn2, SubMenu.add);
bindClick($btn3, SubMenu.del);
其實命令模式的由來是callback function的一個物件導向的替代品。命令模式跟策略模式一樣早已融入到javascript語言中。命令模式需要把運算區塊包裝起來四處傳遞,在Javascript語言中函數作為一個物件本身就可以達到這個效果,即使我們依然需要請求“接收者”,不一定要用物件導向的方式,閉包一樣可以做到通樣功能。
var RefreshMenuBarCommand = function (receiver) {
return {
execute: function () {
receiver.refresh();
}
}
};
var setCommand = function ($btn, command) {
$btn.click(function () {
command.execute();
});
}
var refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar);
setCommand($btn1, refreshMenuBarCommand);
最後我們來做一個巨集命令,也就是一次執行一批命令的狀況。過程中我們也可以省略receiver直接做一個命令物件,會多做receiver本來就是為了讓物件之間解藕,現在我們省略這個過程:
首先一樣做很多個命令
var closeDoorCommand = {
execute: function () {
console.log('關門');
}
};
var openPcCommand = {
execute: function () {
console.log('開電腦');
}
};
var openAcCommand = {
execute: function () {
console.log('開冷氣');
}
};
再來實作巨集裏面新增命令以及執行每個命令的行為
var MarcoCommand = function () {
return {
commandList: [],
add: function (command) {
this.commandList.push(command);
},
execute: function () {
commandList.forEach(function (command) {
command.execute();
});
}
}
};
最後就可以直接新增命令來使用了
var marcoCommand = MarcoCommand();
marcoCommand.add(closeDoorCommand);
marcoCommand.add(openPcCommand);
marcoCommand.add(openAcCommand);
marcoCommand.execute();
以上就是命令模式啦~